package com.uex.dev.manage.common.trace;

import com.uex.dev.manage.common.utils.RandomUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * @author wangc
 * @create 2023/9/27
 * @description
 */
@Slf4j
@Component
public class TraceInterceptor implements HandlerInterceptor {
    private ThreadLocal<Long> timeStart = new ThreadLocal<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            timeStart.set(System.currentTimeMillis());
            String traceId = null;
            String[] traceIdList = request.getParameterValues("traceId");

            if (traceIdList != null && traceIdList.length > 0) {
                traceId = traceIdList[0];
            }

            if (StringUtils.isEmpty(traceId)) {
                traceId = request.getHeader("traceId");
            }

            if (StringUtils.isEmpty(traceId)) {
                traceId = RandomUtils.randomString(10);
            }

            TraceInfo traceInfo = new TraceInfo(traceId);
            traceInfo.setServerIp(getOneLocalIP());

            TraceContext.setTraceInfo(traceInfo);
            MDC.put("traceId", traceId);
            response.addHeader("traceId",TraceContext.getCurrentTraceInfo().getTraceId());
        } catch (Exception e) {

            log.error("write traceId error:", e);
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        TraceContext.clear();
        MDC.clear();
        timeStart.remove();
    }

    private static String getOneLocalIP() {
        List<String> ipList = getLocalIPList();
        if (CollectionUtils.isNotEmpty(ipList)) {
            return ipList.get(0);
        }
        return null;
    }

    private static List<String> getLocalIPList() {
        List<String> ipList = new ArrayList<String>();
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            NetworkInterface networkInterface;
            Enumeration<InetAddress> inetAddresses;
            InetAddress inetAddress;
            String ip;
            while (networkInterfaces.hasMoreElements()) {
                networkInterface = networkInterfaces.nextElement();
                inetAddresses = networkInterface.getInetAddresses();
                while (inetAddresses.hasMoreElements()) {
                    inetAddress = inetAddresses.nextElement();
                    if (inetAddress != null && inetAddress instanceof Inet4Address) {
                        ip = inetAddress.getHostAddress();
                        ipList.add(ip);
                    }
                }
            }
        } catch (SocketException e) {
            log.warn("Fail to getLocalIPList, ", e);
        }
        return ipList;
    }
}
